package it.polimi.traveldream.managers;

import java.util.ArrayList;
import java.util.List;

import it.polimi.traveldream.managers.credentials.UserCredentialManager;
import it.polimi.traveldream.persistence.GruppoUtente;
import it.polimi.traveldream.persistence.Utente;
import it.polimi.traveldream.persistence.dtos.UserDTO;

import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJBContext;
import javax.ejb.Stateless;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.codec.digest.DigestUtils;

@Stateless
public class UserCredentialManagerImpl implements UserCredentialManager {

	@PersistenceContext
	private EntityManager em;

	@Resource
	private EJBContext context;

	// non cattura l'eccezione la soluzione è fare una select query di verifica
	// prima:

	@Override
	public void save(UserDTO pClientDTO) throws UserAlreadyExistsException {
		Utente newUser = convert(pClientDTO);
		if ((em.find(Utente.class, newUser.getEmail())) == null) {
			try {
				em.persist(newUser);
			} catch (EntityExistsException e) {
				throw new UserAlreadyExistsException(e.getMessage(), e);
			}
		} else {
			throw new UserAlreadyExistsException("Duplicate");
		}
	}

	// ho lasciato cmq la funzione precedente
	/*
	 * @Override public void save(UserDTO pClientDTO) throws
	 * UserAlreadyExistsException { Utente newUser = convert(pClientDTO);
	 * 
	 * try { em.persist(newUser); } catch (EntityExistsException e) { throw new
	 * UserAlreadyExistsException(e.getMessage(), e); } }
	 */

	@Override
	public void delete() {
		remove(getPrincipalUser());
	}

	@Override
	@RolesAllowed({ GruppoUtente._CLIENTE, GruppoUtente._IMPIEGATO })
	public void update(UserDTO pNewUserInfo) {
		em.merge(convert(pNewUserInfo));
	}

	public void updates(UserDTO pNewUserInfo) {
		System.out.println("PASSWORD" + pNewUserInfo.getPassword());
		em.merge(convertUpdate(pNewUserInfo));
	}

	public void updateNome(String nome, String mail) {
		System.out.println("@#@#" + nome + mail);
		em.createNamedQuery(Utente.UPDATE_NOME, Utente.class)
				.setParameter("email", mail).setParameter("nome", nome);
		em.flush();

	}

	@Override
	public UserDTO getUserDTO() {
		UserDTO userDTO = convert(getPrincipalUser());
		return userDTO;
	}

	public UserDTO getUserDTOP() {
		UserDTO userDTO = convert2(getPrincipalUser());
		return userDTO;
	}

	@Override
	public UserDTO find(String email) {
		return convert(findUser(email));
	}

	public Utente findUser(String email) {
		return em.find(Utente.class, email);
	}

	public List<Utente> getAllUsers() {
		return em.createNamedQuery(Utente.FIND_ALL, Utente.class)
				.getResultList();
	}

	public List<UserDTO> getAllUsersDTO() {
		List<UserDTO> utentiDTO = new ArrayList<UserDTO>();
		List<Utente> utenti = getAllUsers();

		for (Utente user : utenti) {
			utentiDTO.add(convert(user));
		}

		return utentiDTO;

	}

	public void remove(String email) {
		Utente user = findUser(email);
		em.remove(findUser(email));
	}

	public void remove(Utente user) {
		em.remove(user);
	}

	public void remove(UserDTO user) {

		em.remove(em.find(Utente.class, user.getEmail()));
	}

	public Utente getPrincipalUser() {
		return findUser(getPrincipalEmail());
	}

	public String getPrincipalEmail() {
		return context.getCallerPrincipal().getName();
	}

	public UserDTO convert(Utente user) {
		UserDTO userDTO = new UserDTO();
		userDTO.setEmail(user.getEmail());
		userDTO.setFirstName(user.getNome());
		userDTO.setLastName(user.getCognome());
		userDTO.setIsClient(user.getGruppoUtente().contains(
				GruppoUtente.CLIENTE));
		return userDTO;
	}

	public UserDTO convert2(Utente user) {
		UserDTO userDTO = new UserDTO();
		userDTO.setEmail(user.getEmail());
		userDTO.setFirstName(user.getNome());
		userDTO.setLastName(user.getCognome());
		userDTO.setPassword(user.getPassword());
		userDTO.setIsClient(user.getGruppoUtente().contains(
				GruppoUtente.CLIENTE));
		return userDTO;
	}

	public Utente convert(UserDTO pUserDTO) {
		Utente user = new Utente();
		user.setEmail(pUserDTO.getEmail());
		user.setNome(pUserDTO.getFirstName());
		user.setCognome(pUserDTO.getLastName());
		user.setPassword(DigestUtils.sha256Hex(pUserDTO.getPassword()));
		List<GruppoUtente> groups = new ArrayList<GruppoUtente>();
		if (pUserDTO.getIsClient()) {
			groups.add(GruppoUtente.CLIENTE);
		} else {
			groups.add(GruppoUtente.IMPIEGATO);
		}
		user.setGruppoUtente(groups);

		return user;
	}

	public Utente convertUpdate(UserDTO pUserDTO) {
		Utente user = new Utente();
		user.setEmail(pUserDTO.getEmail());
		user.setNome(pUserDTO.getFirstName());
		user.setCognome(pUserDTO.getLastName());
		user.setPassword(pUserDTO.getPassword());
		List<GruppoUtente> groups = new ArrayList<GruppoUtente>();
		if (pUserDTO.getIsClient()) {
			groups.add(GruppoUtente.CLIENTE);
		} else {
			groups.add(GruppoUtente.IMPIEGATO);
		}
		user.setGruppoUtente(groups);

		return user;
	}

}
